package org.wggds.webservices.io.query.substructuresearch;

import java.util.Collection;
import java.util.HashMap;
import java.util.Map;
import java.util.Vector;

import org.eurocarbdb.application.glycanbuilder.Bond;
import org.eurocarbdb.application.glycanbuilder.Glycan;
import org.eurocarbdb.application.glycanbuilder.Linkage;
import org.eurocarbdb.application.glycanbuilder.Residue;
import org.wggds.webservices.util.MutableInteger;

public class SubStructureSearchImpl implements SubStructureSearch{
	Glycan theQuery;
	Glycan theTransformedQuery;
	
	Map<String,MutableInteger> theQueryComposition;
	Collection<Residue> theQueryResidueList;
	
	
	boolean _completeLeafMatch=false;
	boolean _redEndMatch=false;
	SearchMode theSearchMode=SearchMode.FUZZY;
	
	boolean fuzzyMode=true;
	
	@Override
	public void setQuery(Glycan glycan) {
		theQuery=glycan;
		
		transformQuery();
	}

	@Override
	public void setCompleteLeafMatch(boolean completeLeafMatch) {
		_completeLeafMatch=completeLeafMatch;
	}

	@Override
	public void setRedEndMatch(boolean redEndMatch) {
		_redEndMatch=redEndMatch;
	}

	@Override
	public void searchMode(SearchMode mode) {
		theSearchMode=mode;
		
		transformQuery();
	}
	
	public void transformQuery(){
		if(theQuery==null)
			return;
		
		theTransformedQuery=theQuery.clone();
		
		theQueryResidueList=theTransformedQuery.getAllResidues();
		theQueryComposition=SubStructureSearchImpl.getComposition(theQueryResidueList);
		
		
		if(theSearchMode==SearchMode.LINKAGE_ISOMERS){
			Collection<Residue> residues=theTransformedQuery.getAllResidues();
			for(Residue residue:residues){
				Vector<Linkage> linkages=residue.getChildrenLinkages();
				for(Linkage linkage:linkages){
					for(Bond bond:linkage.getBonds()){
						bond.setChildPosition('?');
						int numberOfPositions=bond.getParentPositions().length;
						
						char[] uncertainPositions=new char[numberOfPositions];
						for(int i=0;i<numberOfPositions;i++){
							uncertainPositions[i]='?';
						}
						
						bond.setParentPositions(uncertainPositions);
					}
				}
			}
			fuzzyMode=true;
		}else if(theSearchMode==SearchMode.STEROCHEMICAL_ISOMERS){
			Collection<Residue> residues=theTransformedQuery.getAllResidues();
			for(Residue residue:residues){
				residue.setAnomericCarbon('?');
				residue.setAnomericState('?');
				residue.setChirality('?');
			}
			fuzzyMode=true;
		}else if(theSearchMode==SearchMode.EQUIVALENT){
			fuzzyMode=false;
		}else if(theSearchMode==SearchMode.FUZZY){
			fuzzyMode=true;
		}
	}

	@Override
	public boolean match(Glycan target) {
		Collection<Residue> targetResidueList=target.getAllResidues();
		
		if(_completeLeafMatch && _redEndMatch && targetResidueList.size()<theQueryResidueList.size()){
			return false;
		}
		
		if(SubStructureSearchImpl.contains(SubStructureSearchImpl.getComposition(targetResidueList),theQueryComposition)==false){
			return false;
		}
		//System.out.println("Proceeding to match: "+_redEndMatch+"|"+_completeLeafMatch+"|"+fuzzyMode);
		if(target.contains(theTransformedQuery, _redEndMatch, _completeLeafMatch,fuzzyMode)){
			return true;
		}else{
			return false;
		}
	}

	@Override
	public boolean match(Glycan query, Glycan target) {
		setQuery(query);
		
		return match(target);
	}
	
	public static boolean contains(Map<String,MutableInteger> host, Map<String,MutableInteger> hosted){
		if(hosted.size()>host.size()){
			return false;
		}
		
		for(String residueType:hosted.keySet()){
			if(host.containsKey(residueType)==false){
				return false;
			}else if(host.get(residueType).mutI<hosted.get(residueType).mutI){
				return false;
			}
		}
		
		return true;
	}
	
	public static Map<String,MutableInteger> getComposition(Collection<Residue> residueList){
		Map<String,MutableInteger> composition=new HashMap<String,MutableInteger>();
		for(Residue r:residueList){
			String name=r.getResidueName();
			if(composition.containsKey(name)==false){
				composition.put(name, new MutableInteger());
			}

			composition.get(name).mutI++;
		}
		
		return composition;
	}
}
